package com.jy.api.shiro.filter;

import cn.hutool.core.util.StrUtil;
import com.jy.api.shiro.token.ApiToken;
import com.jy.api.utils.JwtUtils;
import com.jy.framework.sys.shiro.RedisShiroSessionDAO;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 自定义访问控制
 * 
 */
public class ApiTokenSessionFilter extends AccessControlFilter
{
    private static final Logger log = LoggerFactory.getLogger(ApiTokenSessionFilter.class);
    /**
     * 强制退出后重定向的地址
     */
    @Value("${jy.shiro.loginUrlWeb}")
    private String loginUrlWeb;
    /**
     * 强制退出后重定向的地址
     */
    @Value("${jy.shiro.loginUrlApi}")
    private String loginUrlApi;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired(required = false)
    private RedisShiroSessionDAO redisShiroSessionDAO;
    @Value("${jy.redis.open}")
    private boolean redisOpen;
    @Value("${jy.shiro.redis}")
    private boolean shiroRedis;
    /**
     * 表示是否允许访问；mappedValue就是[urls]配置中拦截器参数部分，如果允许访问返回true，否则false；
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception
    {

        String token = request.getParameter("token");
        if(StrUtil.isEmpty(token)){
            token = ((HttpServletRequest)request).getHeader("token");
        }
        if(StrUtil.isNotEmpty(token)){
            boolean login = appLogin(request, response,  token);
            return login;
        }
        //        todo 由于从 restful 客户端的 request 没有cookie 的session id,所以，每次都要执行 shiro 的认证登录流程，效率上没有使用session 高。
//        new Subject.Builder().sessionCreationEnabled(true).session(null).authenticated(true).buildSubject();
        Subject subject = getSubject(request, response);
//        如果是浏览器会有一个 JSESSIONID ,免登录，postman 会自带 JSESSIONID ， api token 会每次登录
        if(subject!=null && subject.isAuthenticated()){
            return true;
        }
        WebUtils.issueRedirect(request, response, loginUrlWeb);
//        WebUtils.issueRedirect(request, response, "/api/anon/denide");
        return false;
    }

//    private boolean appLogin(ServletRequest request, ServletResponse response,  String token) throws IOException {
//        // 验证Token
//        try {
//Subject subject = getSubject(request, response);

    //            // 登陆
//            ApiToken apiToken = jwtUtils.buildApiToken(token);
//            ThreadContext.bind(subject);
//            subject.login(apiToken);
//            log.info("[API] 登陆成功 : " + token);
////                subject.logout();
//            return true;
//        } catch (Exception e) {
//            log.info("[API]", e);
////                WebUtils.issueRedirect(request, response, loginUrl);
//            // 跳转到绑定页面
//            WebUtils.issueRedirect(request, response, loginUrlApi);
//            return false;
//        }
//    }
    private boolean appLogin(ServletRequest request, ServletResponse response,  String token) throws IOException {
        // 验证Token
        try {
            // 登陆
            String sessionId = jwtUtils.getSessionId(token);
            Session session = redisShiroSessionDAO.readSession(sessionId);
            if (session == null){
                // 跳转到绑定页面
                WebUtils.issueRedirect(request, response, loginUrlApi);
                return false;
            }
            Subject subject = new Subject.Builder().session(session).authenticated(true).buildSubject();
            ThreadContext.bind(subject);
            log.info("[API] 登陆成功 : " + token);
//                subject.logout();
            return true;
        } catch (Exception e) {
            log.info("[API]", e);
//                WebUtils.issueRedirect(request, response, loginUrl);
            // 跳转到绑定页面
            WebUtils.issueRedirect(request, response, loginUrlApi);
            return false;
        }
    }

    /**
     * 表示当访问拒绝时是否已经处理了；如果返回true表示需要继续处理；如果返回false表示该拦截器实例已经处理了，将直接返回即可。
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception
    {
//        Subject subject = getSubject(request, response);
//        if (subject != null)
//        {
//            subject.logout();
//        }
//        saveRequestAndRedirectToLogin(request, response);
//        return false;
        return false;
    }

    // 跳转到登录页
    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException
    {
        WebUtils.issueRedirect(request, response, loginUrlWeb);
    }

    protected String getRequestURL(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        requestURI = requestURI + (StrUtil.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString());
        return requestURI;
    }
}
